package gu.sql2java.manager;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import gu.sql2java.BaseBean;
import gu.sql2java.ForeignKeyMetaData;
import gu.sql2java.IndexMetaData;
import gu.sql2java.RowMetaData;
import gu.sql2java.TableManager;

import static com.google.common.base.Preconditions.*;
import static gu.sql2java.NameUtilities.*;
import static com.google.common.base.MoreObjects.*;
import static gu.sql2java.SimpleLog.*;
import static gu.sql2java.manager.Managers.*;

/**
 * 基于{@link BaseTableManager}实例代理实现接口<I> <br>
 * 
 * @author guyadong
 *
 * @param <I> 接口类型
 */
public class TableManagerDecorator<I extends TableManager<?>> implements InvocationHandler{
	private final Class<I> interfaceClass;
	final BaseTableManager<? extends BaseBean> delegate;	
	private final Map<Method, Invoker> invokers = Maps.newLinkedHashMap();
	@SuppressWarnings("rawtypes")
	private final Class<? extends BaseTableManager> implClass;
	final RowMetaData metaData; 
	private static boolean debug = false;
	/**
	 * 构造方法
	 * 
	 * @param interfaceClass 接口类
	 * @param delegate 实现接口的实例
	 */
	TableManagerDecorator(Class<I> interfaceClass, BaseTableManager<? extends BaseBean> delegate) {
		checkType(interfaceClass,delegate);
		this.interfaceClass = interfaceClass;
		this.delegate = delegate;
		this.implClass = delegate.getClass();
		this.metaData = delegate.metaData;
		try {
			compile();
		} catch (Exception e) {
			Throwables.throwIfUnchecked(e);
			throw new RuntimeException(e);
		}
	}
	/**
	 * 构造方法
	 * 
	 * @param interfaceClass 接口类
	 * @param tablename 接口类对应的表名
	 */
	TableManagerDecorator(Class<I> interfaceClass, String tablename) {
		this(interfaceClass,new BaseTableManager<BaseBean>(tablename));
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		return checkNotNull(invokers.get(method),"UNSUPPORT method %s",method).invoke(args);
	}
	
	/**
	 * @return 根据当前对象创建新的接口实例{@link Proxy}
	 */
	public final I proxyInstance(){
		return interfaceClass.cast(Proxy.newProxyInstance(
				interfaceClass.getClassLoader(),
				new Class<?>[]{ interfaceClass},
				this));
	}
	
	@Override
	public String toString(){
		StringBuffer builder = new StringBuffer();
		String simulateClassName = interfaceClass.getSimpleName() + "Decorator";
		String simulateTableManagerClass = BaseTableManager.class.getName() + "<"  + metaData.beanType.getName() + ">";
		builder.append("class ").append(simulateClassName).append(" implements ").append(interfaceClass.getName()).append("{\n");
		builder.append("    private final ").append(simulateTableManagerClass).append(" delegate;\n");
		builder.append("    public ").append(simulateClassName).append("(").append(simulateTableManagerClass).append(" delegate){\n");
		builder.append("        this.delegate = delegate\n");
		builder.append("    }\n");
		for(Invoker invoker:invokers.values()){
			builder.append(invoker);
		}
		builder.append("}\n");
		return builder.toString();
	}
	/**
	 * 检查参数类型合法性，不匹配则抛出异常
	 * @param interfaceClass
	 * @param delegate
	 */
	private static void checkType(Class<?> interfaceClass, BaseTableManager<?> delegate){
		checkArgument(interfaceClass != null, "interfaceClass is null");
		checkArgument(delegate != null, "delegate is null");
		checkArgument(delegate.metaData.managerInterfaceClass.equals(interfaceClass), 
				"MISMATCH interface class of delegate(%s) with %s",
				delegate.metaData.managerInterfaceClass.getSimpleName(),
				interfaceClass.getName());
	}
	/**
	 * 创建{@code interfaceClass}接口实例
	 * @param interfaceClass 接口类
	 * @param delegate 代理类实例 
	 * @return {@code interfaceClass}接口实例
	 */
	static final <I extends TableManager<?>>I makeInterfaceInstance(Class<I> interfaceClass,BaseTableManager<?> delegate){
		return new TableManagerDecorator<I>(interfaceClass,delegate).proxyInstance();
	}
	/**
	 * 创建{@code interfaceClass}接口实例
	 * @param interfaceClass 接口类
	 * @param tablename 接口类对应的表名
	 * @return {@code interfaceClass}接口实例
	 */
	static final <I extends TableManager<?>>I makeInterfaceInstance(Class<I> interfaceClass,String tablename){
		return new TableManagerDecorator<I>(interfaceClass,tablename).proxyInstance();
	}
	/**
	 * 创建接口实例
	 * @param delegate 代理类实例 
	 * @return 接口实例
	 */
	public static final <I extends TableManager<?>>TableManager<?> makeInterfaceInstance(BaseTableManager<?> delegate){
		checkArgument(delegate != null ,"delegate is null");
		checkArgument(delegate.metaData.managerInterfaceClass != null,"delegate.metaData.managerInterfaceClass is null");
		return makeInterfaceInstance(delegate.metaData.managerInterfaceClass,delegate);
	}
	/**
	 * 创建接口实例
	 * @param tablename 接口类对应的表名
	 * @return 接口实例
	 */
	static final <I extends TableManager<?>>TableManager<?> makeInterfaceInstance(String tablename){
		return makeInterfaceInstance(getBaseTableManager(tablename));
	}
	/**
	 * 设置是否输出调试信息标志
	 * @param debug 
	 */
	static void setDebug(boolean debug) {
		TableManagerDecorator.debug = debug;
	}

	private static final String M_LOADBYPRIMARYKEY = "loadByPrimaryKey";
	private static final String D_LOADBYPKS = "loadByPks";
	private static final String M_LOADBYPRIMARYKEYCHECKED = "loadByPrimaryKeyChecked";
	private static final String M_EXISTSPRIMARYKEY = "existsPrimaryKey";
	private static final String M_CHECKDUPLICATE = "checkDuplicate";
	private static final String D_CHECKDUPLICATEBYPK = "checkDuplicateByPk";
	private static final String M_DELETEBYPRIMARYKEY = "deleteByPrimaryKey";
	private static final String D_DELETEBYPKS = "deleteByPks";
	private static final String M_TOPRIMARYKEYLIST = "toPrimaryKeyList";
	private static final String P_ADDJUNCTION = "addJunction(With(\\w+))?";
	private static final String D_ADDJUNCTION = "addJunction";
	private static final String P_DELETEJUNCTION = "deleteJunction(With(\\w+))?";
	private static final String D_DELETEJUNCTION = "deleteJunction";
	private static final String P_GETIMPORTEDBEANS = "get(\\w+)sBy(\\w+)$";
	private static final String D_GETIMPORTEDBEANS = "getImportedBeans";
	private static final String P_GETIMPORTEDBEANSASLIST = "get(\\w+)sBy(\\w+)AsList";
	private static final String D_GETIMPORTEDBEANSASLIST = "getImportedBeansAsList";
	private static final String P_DELETEIMPORTEDBEANS = "delete(\\w+)sBy(\\w+)";
	private static final String D_DELETEIMPORTEDBEANS = "deleteImportedBeans";
	private static final String P_SETIMPORTEDBEANS = "set(\\w+)sBy(\\w+)";
	private static final String D_SETIMPORTEDBEANS = "setImportedBeans";
	private static final String M_SAVE = "save";
	private static final String D_SAVEFULLY = "saveFully";
	private static final String M_SAVEASTRANSACTION = "saveAsTransaction";
	private static final String D_SAVEFULLYASTRANSACTION = "saveFullyAsTransaction";
	private static final String P_GETREFERENCEDBEAN = "getReferencedBy(\\w+)";
	private static final String D_GETREFERENCEDBEAN = "getReferencedBean";
	private static final String P_SETREFERENCEDBEAN = "setReferencedBy(\\w+)";
	private static final String D_SETREFERENCEDBEAN = "setReferencedBean";
	private static final String P_LOADBYINDEX = "loadByIndex(\\w+)";
	private static final String D_LOADBYINDEX = "loadByIndex";
	private static final String P_LOADUNIQUEBYINDEXCHECKED = "loadByIndex(\\w+)Checked";
	private static final String D_LOADUNIQUEBYINDEXCHECKED = "loadUniqueByIndexChecked";
	private static final String D_LOADBYINDEXFORINDICES = "loadByIndexForIndices";
	private static final String D_LOADUNIQUEBYINDEX = "loadUniqueByIndex";
	private static final String P_LOADBYINDEXASLIST = "loadByIndex(\\w+)AsList";
	private static final String D_LOADBYINDEXASLIST = "loadByIndexAsList";
	private static final String P_DELETEBYINDEX = "deleteByIndex(\\w+)";
	private static final String D_DELETEBYINDEX = "deleteByIndex";
	private static final String P_LOADVIAJUNCTIONASLIST = "loadVia(\\w+)AsList";
	private static final String D_LOADVIAJUNCTIONASLIST = "loadViaJunctionAsList";
	private static final String P_LISTOFSELFREF = "listOf(\\w+)";
	private static final String D_LISTOFSELFREF = "listOfSelfRef";
	private static final String P_LEVELOFSELFREF = "levelOf(\\w+)";
	private static final String D_LEVELOFSELFREF = "levelOfSelfRef";
	private static final String P_ISCYCLEOFSELFREF = "isCycleOn(\\w+)";
	private static final String D_ISCYCLEOFSELFREF = "isCycleOfSelfRef";
	private static final String P_CHECKCYCLEOFSELFREF = "checkCycleOf(\\w+)";
	private static final String D_CHECKCYCLEOFSELFREF = "checkCycleOfSelfRef";
	private static final String P_TOPOFSELFREF = "topOf(\\w+)";
	private static final String D_TOPOFSELFREF = "topOfSelfRef";
	private static final String P_CHILDLISTOFSELFREF = "childListBy(\\w+)";
	private static final String D_CHILDLISTOFSELFREF = "childListOfSelfRef";
	private static final String P_CHILDRENOFSELFREF = "childrenBy(\\w+)";
	private static final String D_CHILDRENOFSELFREF = "childrenOfSelfRef";
	private static final String P_CHILDRENOFBEANSOFSELFREF = "childrenOfBeansBy(\\w+)";
	private static final String D_CHILDRENOFBEANSOFSELFREF = "childrenOfBeansOfSelfRef";
	private static final String P_CHILDRENOFPKSOFSELFREF = "childrenOfPksBy(\\w+)";
	private static final String D_CHILDRENOFPKSOFSELFREF = "childrenOfPksOfSelfRef";
	
	private static final Comparator<Method> METHOD_COMPARATOR = new Comparator<Method>() {
		@Override
		public int compare(Method o1, Method o2) {
			return signatureOf(o1).compareTo(signatureOf(o2));
		}
	};
	private static boolean declaredBySuper(Method method,Class<?> superClazz){
		if(method.getDeclaringClass().equals(superClazz)){
			return true;
		}
		for(Class<?> clazz:superClazz.getInterfaces()){
			if(declaredBySuper(method,clazz)){
				return true;
			}
		}
		return false;
	} 
	/**
	 * 向上递归查找指定的方法,找不到指定的方法则抛出异常
	 * @param clazz
	 * @param name
	 * @param parameterTypes
	 * @return 方法对象
	 * @throws NoSuchMethodException 找不到指定的方法
	 * @throws SecurityException
	 */
	private static Method recursiveGetDeclaredMethod(Class<?> clazz,String name, Class<?>... parameterTypes)
	        throws NoSuchMethodException, SecurityException {
		try {
			return clazz.getDeclaredMethod(name, parameterTypes);
		} catch (NoSuchMethodException e) {
			Class<?> superClass = clazz.getSuperclass();
			if(null != superClass){
				return recursiveGetDeclaredMethod(superClass,name,parameterTypes);
			}
			throw e;
		}
	}
	
	/**
	 * 在代理类({@link #implClass})查找指定的方法,找不到指定的方法则抛出异常
	 * @param name
	 * @param parameterTypes
	 * @return 方法对象
	 * @throws NoSuchMethodException 找不到指定的方法
	 * @throws SecurityException
	 */
	private Method getDeclaredMethod(String name, Class<?>... parameterTypes)
	        throws NoSuchMethodException, SecurityException {
		return recursiveGetDeclaredMethod(implClass, name, parameterTypes);
	}
	private NoSuchMethodException makeNoSuchMethodException(Method def){
		return new NoSuchMethodException(logString("NO FOUND MATCHED METHOD for %s in %s",def,implClass));
	}
	private Invoker compile(Method def) throws NoSuchMethodException, SecurityException{
		Method impl;
		String name = def.getName();
		if(declaredBySuper(def,TableManager.class)){
			impl = BaseTableManager.class.getDeclaredMethod(name, def.getParameterTypes());
			return new MethodInvoker(def, impl, delegate);
		}
		
		switch(name){
		case M_LOADBYPRIMARYKEY:
			return loadByPrimaryKey(def);
		case M_LOADBYPRIMARYKEYCHECKED:
			impl = getDeclaredMethod(M_LOADBYPRIMARYKEYCHECKED, Object[].class);
			return new MethodInvoker(def, impl, delegate);
		case M_EXISTSPRIMARYKEY:
			impl = getDeclaredMethod(M_EXISTSPRIMARYKEY, Object[].class);
			return new MethodInvoker(def, impl, delegate);
		case M_CHECKDUPLICATE:
			impl = getDeclaredMethod(D_CHECKDUPLICATEBYPK, Object.class);
			return new MethodInvoker(def, impl, delegate);
		case M_DELETEBYPRIMARYKEY:
			return deleteByPrimaryKey(def);
		case M_TOPRIMARYKEYLIST:
			return toPrimaryKeyList(def);
		case M_SAVE:
			return saveFully(def);
		case M_SAVEASTRANSACTION:
			return saveFullyAsTransaction(def);
		default:
			if(name.matches(P_ADDJUNCTION)){
				return addJunction(def);
			}
			if(name.matches(P_DELETEJUNCTION)){
				return deleteJunction(def);
			}
			if(name.matches(P_GETIMPORTEDBEANSASLIST)){
				return getImportedBeansAsList(def);
			}
			if(name.matches(P_GETIMPORTEDBEANS)){
				return getImportedBeans(def);
			}
			if(name.matches(P_DELETEIMPORTEDBEANS)){
				return deleteImportedBeans(def);
			}
			if(name.matches(P_SETIMPORTEDBEANS)){
				return setImportedBeans(def);
			}
			if(name.matches(P_GETREFERENCEDBEAN)){
				return getReferencedBean(def);
			}
			if(name.matches(P_SETREFERENCEDBEAN)){
				return setReferencedBean(def);
			}
			if(name.matches(P_LOADBYINDEXASLIST)){
				return loadByIndexAsList(def);
			}
			if(name.matches(P_LOADUNIQUEBYINDEXCHECKED)){
				return loadUniqueByIndexChecked(def);
			}
			if(name.matches(P_LOADBYINDEX)){
				return loadByIndex(def);
			}

			if(name.matches(P_DELETEBYINDEX)){
				return deleteByIndex(def);
			}
			if(name.matches(P_LOADVIAJUNCTIONASLIST)){
				return loadViaJunctionAsList(def);
			}
			if(name.matches(P_LISTOFSELFREF)){
				return listOfSelfRef(def);
			}
			if(name.matches(P_LEVELOFSELFREF)){
				return levelOfSelfRef(def);
			}
			if(name.matches(P_ISCYCLEOFSELFREF)){
				return isCycleOfSelfRef(def);
			}
			if(name.matches(P_CHECKCYCLEOFSELFREF)){
				return checkCycleOfSelfRef(def);
			}
			
			if(name.matches(P_TOPOFSELFREF)){
				return topOfSelfRef(def);
			}
			if(name.matches(P_CHILDLISTOFSELFREF)){
				return childListOfSelfRef(def);
			}
			if(name.matches(P_CHILDRENOFSELFREF)){
				return childrenOfSelfRef(def);
			}
			if(name.matches(P_CHILDRENOFBEANSOFSELFREF)){
				return childrenOfSelfRefForBeans(def);
			}
			if(name.matches(P_CHILDRENOFPKSOFSELFREF)){
				return childrenOfSelfRefForPks(def);
			}
			throw new IllegalArgumentException(logString("NO SUCH METHOD maped %s",def.getName()));
		}		
	}
	
	private void addObjectInvoker(String methodName,Class<?>...parameterTypes) throws NoSuchMethodException, SecurityException{
		Method method = Object.class.getMethod(methodName, parameterTypes);
		ObjectInvoker objectInvoker = new ObjectInvoker(method);
		invokers.put(method, objectInvoker);
		if(debug){
			log("{}",objectInvoker);
		}
	}
	private void compile(Method[] methods) throws NoSuchMethodException, SecurityException{
		Arrays.sort(methods,METHOD_COMPARATOR);
		for(Method method : methods){
			Invoker invokder = compile(method);
			invokers.put(method, invokder);
//			Invoker old = invokers.put(method, invokder);
//			checkState(old == null,"duplicated entry for method %s",signatureOf(method));
			if(debug){
				log("{}",invokder);
			}
		}
	}
	private void compile() throws NoSuchMethodException, SecurityException{
		addObjectInvoker("toString");
		addObjectInvoker("hashCode");
		addObjectInvoker("equals",Object.class);
		compile(TableManager.class.getMethods());
		/** 过滤所有桥接方法 */
		Method[] noBridgeMethods = Arrays.stream(interfaceClass.getDeclaredMethods())
				.filter(m->!m.isBridge()).toArray(Method[]::new);
		compile(noBridgeMethods);
	}
    //////////////////////////////////////
    // PRIMARY KEY METHODS
    //////////////////////////////////////
	
	private MethodInvoker loadByPrimaryKey(Method def) throws NoSuchMethodException, SecurityException{
		Method impl;
		Class<?>[] paramTypes = def.getParameterTypes();
		checkArgument(paramTypes.length == metaData.primaryKeyCount,"only %s parameter required for %s",metaData.primaryKeyCount,def);
		if(Arrays.equals(metaData.primaryKeyTypes, paramTypes)){
			impl = getDeclaredMethod(M_LOADBYPRIMARYKEY, Object[].class);
		}else {
			if(metaData.primaryKeyCount == 1){
				if(Collection.class.isAssignableFrom(paramTypes[0])){
					impl = getDeclaredMethod(D_LOADBYPKS, Collection.class);
				}else{
					Class<?> pkType = metaData.columnTypeOf(metaData.primaryKeyIds[0]);
					Object pkArray = Array.newInstance(pkType, 0);
					if(paramTypes[0] == pkArray.getClass()){
						impl = getDeclaredMethod(D_LOADBYPKS, Object[].class);
					}else {
						throw makeNoSuchMethodException(def);
					}
				}
			}else{
				throw makeNoSuchMethodException(def);
			}
		}
		return new MethodInvoker(def, impl, delegate);
	}
	private MethodInvoker deleteByPrimaryKey(Method def) throws NoSuchMethodException, SecurityException{
		Method impl;
		Class<?>[] paramTypes = def.getParameterTypes();
		checkArgument(paramTypes.length == metaData.primaryKeyCount,"%s parameter required for %s",metaData.primaryKeyCount,def);
		if(Arrays.equals(metaData.primaryKeyTypes, paramTypes)){
			impl = getDeclaredMethod(M_DELETEBYPRIMARYKEY, Object[].class);
		}else {
			if(Collection.class.isAssignableFrom(paramTypes[0])){
				impl = getDeclaredMethod(D_DELETEBYPKS, Collection.class);
			}else{
				Class<?> pkType = metaData.columnTypeOf(metaData.primaryKeyIds[0]);
				Object pkArray = Array.newInstance(pkType, 0);
				if(paramTypes[0] == pkArray.getClass()){
					impl = getDeclaredMethod(D_DELETEBYPKS, Object[].class);
				}else {
					throw makeNoSuchMethodException(def);					
				}
			}
		}
		return new MethodInvoker(def, impl, delegate);
	}
	
    //////////////////////////////////////
    // GET/SET IMPORTED KEY BEAN METHOD
    //////////////////////////////////////
	
	private MethodInvoker getImportedBeans(Method def)throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		Pattern pattern = Pattern.compile(P_GETIMPORTEDBEANS);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_GETIMPORTEDBEANS);
		String importeBeanName = matcher.group(1);
		String readableName = matcher.group(2);
		ForeignKeyMetaData importedKey = RowMetaData.getForeignKey(importeBeanName,readableName, metaData.alias);
		Method impl = getDeclaredMethod(D_GETIMPORTEDBEANS, 
				paramBuilder().add(importedKey.name.getClass(),paramTypes).normalizeLast(1, Object[].class).build());
		return new MethodInvoker(def, impl, delegate, importedKey.name);
	}

	private MethodInvoker getImportedBeansAsList(Method def)throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		
		switch(paramTypes.length){
		case 1:{
			// DO NOTHING
			break;
		}
		case 3:{
			if(BaseBean.class.isAssignableFrom(paramTypes[0]) && int.class == paramTypes[1] && int.class == paramTypes[2]){
				// DO NOTHING
			}else{
				paramTypes = new Class<?>[]{Object[].class};
			}
			break;
		}
		default:{
			paramTypes = new Class<?>[]{Object[].class};
			break;
		}
		}
		Pattern pattern = Pattern.compile(P_GETIMPORTEDBEANSASLIST);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_GETIMPORTEDBEANSASLIST);
		String importeBeanName = matcher.group(1);
		String readableName = matcher.group(2);
		ForeignKeyMetaData importedKey = RowMetaData.getForeignKey(importeBeanName,readableName, metaData.alias);
		Method impl = getDeclaredMethod(D_GETIMPORTEDBEANSASLIST, 
				paramBuilder().add(importedKey.name.getClass(),paramTypes).genericNormalize(1,Object[].class).build());
		return new MethodInvoker(def, impl, delegate, importedKey.name);
	}
	private MethodInvoker deleteImportedBeans(Method def)throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		Pattern pattern = Pattern.compile(P_DELETEIMPORTEDBEANS);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_DELETEIMPORTEDBEANS);
		String importeBeanName = matcher.group(1);
		String readableName = matcher.group(2);
		ForeignKeyMetaData importedKey = RowMetaData.getForeignKey(importeBeanName,readableName, metaData.alias);
		Method impl = getDeclaredMethod(D_DELETEIMPORTEDBEANS, 
				paramBuilder().add(importedKey.name.getClass(),paramTypes).normalizeLast(1, Object[].class).build());
		return new MethodInvoker(def, impl, delegate, importedKey.name);
	}
	private MethodInvoker setImportedBeans(Method def)throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		checkArgument(paramTypes.length == 2,"2 parameter required for %s",def.getName());
		Pattern pattern = Pattern.compile(P_SETIMPORTEDBEANS);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_SETIMPORTEDBEANS);
		String importeBeanName = matcher.group(1);
		String readableName = matcher.group(2);
		ForeignKeyMetaData importedKey = RowMetaData.getForeignKey(importeBeanName,readableName, metaData.alias);
		Method impl = getDeclaredMethod(D_SETIMPORTEDBEANS, 
				paramBuilder().add(importedKey.name.getClass(),wrapBaseBean(paramTypes)).build());
		return new MethodInvoker(def, impl, delegate, importedKey.name);
	}
	
    //_____________________________________________________________________
    //
    // SAVE 
    //_____________________________________________________________________
	
	private MethodInvoker saveFully(Method def)throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		int paramCount = metaData.foreignKeys.size() + metaData.getImportedKeys().size() + 1;
		checkArgument(paramTypes.length == paramCount,"%s parameter required for %s",paramCount,def.getName());		
		Method impl = getDeclaredMethod(D_SAVEFULLY, BaseBean.class,Object[].class);

		return new SaveFullyInvoker(def, impl);
	}
	private MethodInvoker saveFullyAsTransaction(Method def)throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		int paramCount = metaData.foreignKeys.size() + metaData.getImportedKeys().size() + 1;
		checkArgument(paramTypes.length == paramCount,"%s parameter required for %s",paramCount,def.getName());
		Method impl = getDeclaredMethod(D_SAVEFULLYASTRANSACTION, BaseBean.class,Object[].class);
		return new SaveFullyInvoker(def, impl);
	}
	
    //////////////////////////////////////
    // GET/SET FOREIGN KEY BEAN METHOD
    //////////////////////////////////////
	
	private MethodInvoker getReferencedBean(Method def)throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
		Pattern pattern = Pattern.compile(P_GETREFERENCEDBEAN);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_GETREFERENCEDBEAN);
		String readableName = matcher.group(1);
		ForeignKeyMetaData foreignKey = metaData.getForeignKeyByRn(readableName);
		Method impl = getDeclaredMethod(D_GETREFERENCEDBEAN, foreignKey.name.getClass(), BaseBean.class);
		return new MethodInvoker(def, impl, delegate, foreignKey.name);
	}
	private MethodInvoker setReferencedBean(Method def)throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		checkArgument(paramTypes.length == 2,"2 parameter required for %s",def.getName());
		Pattern pattern = Pattern.compile(P_SETREFERENCEDBEAN);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_SETREFERENCEDBEAN);
		String readableName = matcher.group(1);
		ForeignKeyMetaData foreignKey = metaData.getForeignKeyByRn(readableName);
		Method impl = getDeclaredMethod(D_SETREFERENCEDBEAN, 
				paramBuilder().add(foreignKey.name.getClass(),wrapBaseBean(paramTypes)).build());
		return new MethodInvoker(def, impl, delegate, foreignKey.name);
	}
	
    //_____________________________________________________________________
    //
    // USING INDICES
    //_____________________________________________________________________
	
	private MethodInvoker loadByIndex(Method def)throws NoSuchMethodException, SecurityException{
		Method impl;
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		Pattern pattern = Pattern.compile(P_LOADBYINDEX);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_LOADBYINDEX);
		String readableName = matcher.group(1);
		IndexMetaData index = metaData.getIndexCheckedByRn(readableName);
		if(index.unique){
			Object indexArray = Array.newInstance(metaData.jdbcTypeOf(metaData.indexIdArray(index.name)[0]), 0);
			if(paramTypes[0].equals(indexArray.getClass()) && index.columns.size() == 1){
				impl = getDeclaredMethod(D_LOADBYINDEXFORINDICES, index.name.getClass(), Object[].class);
			} else if(Collection.class.equals(paramTypes[0]) && index.columns.size() == 1){
					impl = getDeclaredMethod(D_LOADBYINDEXFORINDICES, index.name.getClass(), Collection.class);
			}else if(Arrays.equals(metaData.indexTypeArray(index.name), paramTypes)){
				impl = getDeclaredMethod(D_LOADUNIQUEBYINDEX, index.name.getClass(), Object[].class);
			} else{
				throw makeNoSuchMethodException(def);
			}
		}else{
			impl = getDeclaredMethod(D_LOADBYINDEX, index.name.getClass(), Object[].class);
		}
		return new MethodInvoker(def, impl, delegate, index.name);
	}
	private MethodInvoker loadUniqueByIndexChecked(Method def)throws NoSuchMethodException, SecurityException{
		Method impl;
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		Pattern pattern = Pattern.compile(P_LOADUNIQUEBYINDEXCHECKED);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_LOADUNIQUEBYINDEXCHECKED);
		String readableName = matcher.group(1);
		IndexMetaData index = metaData.getIndexCheckedByRn(readableName);
		if(Arrays.equals(metaData.indexTypeArray(index.name), paramTypes)){
			impl = getDeclaredMethod(D_LOADUNIQUEBYINDEXCHECKED, index.name.getClass(), Object[].class);
		} else{
			throw makeNoSuchMethodException(def);
		}
		return new MethodInvoker(def, impl, delegate, index.name);
	}
	private MethodInvoker loadByIndexAsList(Method def)throws NoSuchMethodException, SecurityException{
		String methodName = def.getName();
		Pattern pattern = Pattern.compile(P_LOADBYINDEXASLIST);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_LOADBYINDEXASLIST);
		String readableName = matcher.group(1);
		IndexMetaData index = metaData.getIndexCheckedByRn(readableName);
		Method impl = getDeclaredMethod(D_LOADBYINDEXASLIST, index.name.getClass(), Object[].class);
		return new MethodInvoker(def, impl, delegate, index.name);
	}
	private MethodInvoker deleteByIndex(Method def)throws NoSuchMethodException, SecurityException{
		String methodName = def.getName();
		Pattern pattern = Pattern.compile(P_DELETEBYINDEX);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_DELETEBYINDEX);
		String readableName = matcher.group(1);
		IndexMetaData index = metaData.getIndexCheckedByRn(readableName);
		Method impl = getDeclaredMethod(D_DELETEBYINDEX, index.name.getClass(), Object[].class);
		return new MethodInvoker(def, impl, delegate, index.name);
	}
	
    //_____________________________________________________________________
    //
    // MANY TO MANY: LOAD OTHER BEAN VIA JUNCTION TABLE
    //_____________________________________________________________________
	
	private MethodInvoker loadViaJunctionAsList(Method def)throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		checkArgument(paramTypes.length == 1 || paramTypes.length == 3,"1 or 3 parameter required for %s",def.getName());
		Pattern pattern = Pattern.compile(P_LOADVIAJUNCTIONASLIST);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_LOADVIAJUNCTIONASLIST);
		String coreClassName = matcher.group(1);
		String junctionTable = RowMetaData.getRowMetaDataByCoreClassName(coreClassName, metaData.alias).tablename;
		paramBuilder().add(junctionTable.getClass(),wrapBaseBean(paramTypes)).build();
		Method impl = getDeclaredMethod(D_LOADVIAJUNCTIONASLIST, 
				paramBuilder().add(junctionTable.getClass(),wrapBaseBean(paramTypes)).build());
		return new MethodInvoker(def, impl, delegate, junctionTable);
	}
	private MethodInvoker addJunction(Method def) throws NoSuchMethodException, SecurityException{
		String name = def.getName();
		Type[] gTypes = def.getGenericParameterTypes();
		Class<?>[] paramTypes = def.getParameterTypes();
		checkArgument(paramTypes.length == 2,"only 2 parameter required for %s",name);
		RowMetaData junctionTable = metaData.getJunctionTableFor(gTypes[1]);
		Method impl = getDeclaredMethod(D_ADDJUNCTION, 
				paramBuilder().add(junctionTable.tablename.getClass(),wrapBaseBean(paramTypes)).build());
		return new MethodInvoker(def, impl, delegate, junctionTable.tablename);
	}

	private MethodInvoker deleteJunction(Method def) throws NoSuchMethodException, SecurityException{
		Type[] gTypes = def.getGenericParameterTypes();
		Class<?>[] paramTypes = def.getParameterTypes();
		checkArgument(paramTypes.length == 2,"only 2 parameter required for %s",def.getName());
		RowMetaData junctionTable = metaData.getJunctionTableFor(gTypes[1]);
		Method impl = getDeclaredMethod(D_DELETEJUNCTION, 
				paramBuilder().add(junctionTable.tablename.getClass(),wrapBaseBean(paramTypes)).build());
		return new MethodInvoker(def, impl, delegate, junctionTable.tablename);
	}

	private MethodInvoker toPrimaryKeyList(Method def) throws NoSuchMethodException, SecurityException{
		Method impl;
		Class<?>[] paramTypes = def.getParameterTypes();
		Class<?> pkType = metaData.columnTypeOf(metaData.primaryKeyIds[0]);
		checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
		if(Collection.class.isAssignableFrom(paramTypes[0])){
			impl = getDeclaredMethod(M_TOPRIMARYKEYLIST, Class.class,Collection.class);
		}else{			
			Object beanArray = Array.newInstance(metaData.beanType, 0);
			if(paramTypes[0] == beanArray.getClass()){
				impl = getDeclaredMethod(M_TOPRIMARYKEYLIST, Class.class,BaseBean[].class);
			}else {
				throw makeNoSuchMethodException(def);
			}
		}
		return new MethodInvoker(def, impl, delegate, pkType);
	}

    //_____________________________________________________________________
    //
    // SELF-REFERENCE
    //_____________________________________________________________________
	
	private MethodInvoker listOfSelfRef(Method def) throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
		Pattern pattern = Pattern.compile(P_LISTOFSELFREF);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_LISTOFSELFREF);
		String readableName = matcher.group(1);
		ForeignKeyMetaData selfRefKey = metaData.getSelfRefKeyByRn(readableName);
		Method impl = getDeclaredMethod(D_LISTOFSELFREF, 
				paramBuilder().add(selfRefKey.name.getClass(),paramTypes).genericNormalize(1, Object[].class).build());
		return new MethodInvoker(def, impl, delegate, selfRefKey.name);
	}
	private MethodInvoker levelOfSelfRef(Method def) throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
		Pattern pattern = Pattern.compile(P_LEVELOFSELFREF);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_LEVELOFSELFREF);
		String readableName = matcher.group(1);
		ForeignKeyMetaData selfRefKey = metaData.getSelfRefKeyByRn(readableName);
		Method impl = getDeclaredMethod(D_LEVELOFSELFREF, 
				paramBuilder().add(selfRefKey.name.getClass(),paramTypes).genericNormalize(1, Object[].class).build());
		return new MethodInvoker(def, impl, delegate, selfRefKey.name);
	}
	private MethodInvoker isCycleOfSelfRef(Method def) throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
		Pattern pattern = Pattern.compile(P_ISCYCLEOFSELFREF);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_ISCYCLEOFSELFREF);
		String readableName = matcher.group(1);
		ForeignKeyMetaData selfRefKey = metaData.getSelfRefKeyByRn(readableName);
		Method impl = getDeclaredMethod(D_ISCYCLEOFSELFREF, 
				paramBuilder().add(selfRefKey.name.getClass(),paramTypes).genericNormalize(1, Object[].class).build());
		return new MethodInvoker(def, impl, delegate, selfRefKey.name);
	}
	private MethodInvoker checkCycleOfSelfRef(Method def) throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
		Pattern pattern = Pattern.compile(P_CHECKCYCLEOFSELFREF);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_CHECKCYCLEOFSELFREF);
		String readableName = matcher.group(1);
		ForeignKeyMetaData selfRefKey = metaData.getSelfRefKeyByRn(readableName);
		Method impl = getDeclaredMethod(D_CHECKCYCLEOFSELFREF, 
				paramBuilder().add(selfRefKey.name.getClass(),paramTypes).genericNormalize(1, Object.class).build());
		return new MethodInvoker(def, impl, delegate, selfRefKey.name);
	}
	private MethodInvoker topOfSelfRef(Method def) throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
		Pattern pattern = Pattern.compile(P_TOPOFSELFREF);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",P_TOPOFSELFREF);
		String readableName = matcher.group(1);
		ForeignKeyMetaData selfRefKey = metaData.getSelfRefKeyByRn(readableName);
		Method impl = getDeclaredMethod(D_TOPOFSELFREF, 
				paramBuilder().add(selfRefKey.name.getClass(),paramTypes).genericNormalize(1, Object[].class).build());
		return new MethodInvoker(def, impl, delegate, selfRefKey.name);
	}
	private MethodInvoker childListOfSelfRef(Method def) throws NoSuchMethodException, SecurityException{
		return methodOfRecursionOfSelfRef(def,P_CHILDLISTOFSELFREF,D_CHILDLISTOFSELFREF, Object[].class);
	}
	private MethodInvoker childrenOfSelfRef(Method def) throws NoSuchMethodException, SecurityException{
		return methodOfRecursionOfSelfRef(def,P_CHILDRENOFSELFREF,D_CHILDRENOFSELFREF, Object[].class);
	}
	private MethodInvoker childrenOfSelfRefForBeans(Method def) throws NoSuchMethodException, SecurityException{
		return methodOfRecursionOfSelfRef(def,P_CHILDRENOFBEANSOFSELFREF,D_CHILDRENOFBEANSOFSELFREF, null);
	}
	private MethodInvoker childrenOfSelfRefForPks(Method def) throws NoSuchMethodException, SecurityException{
		return methodOfRecursionOfSelfRef(def,P_CHILDRENOFPKSOFSELFREF,D_CHILDRENOFPKSOFSELFREF, null);
	}
	private MethodInvoker methodOfRecursionOfSelfRef(Method def,String regex,String delegateName, Class<?> normalizeFirstArgType) throws NoSuchMethodException, SecurityException{
		Class<?>[] paramTypes = def.getParameterTypes();
		String methodName = def.getName();
		checkArgument(paramTypes.length == 1,"only 1 parameter required for %s",def.getName());
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(methodName);
		checkArgument(matcher.matches(),"INVALID method name pattern,%s required",regex);
		String readableName = matcher.group(1);
		ForeignKeyMetaData selfRefKey = metaData.getSelfRefKeyByRn(readableName);
		Method impl = getDeclaredMethod(delegateName, 
				paramBuilder().add(selfRefKey.name.getClass(),paramTypes).genericNormalize(1, normalizeFirstArgType).build());
		return new MethodInvoker(def, impl, delegate, selfRefKey.name);
	}

	private static final boolean isVoid(Class<?> clazz){
		return "void".equals(clazz.getName());
	}
	
	private static final Class<?> wrapBaseBean(Class<?> type){
		if(null != type){
			if(type.isArray()){
				Class<?> componentType = wrapBaseBean(type.getComponentType());
				if(componentType != type.getComponentType()){
					return Array.newInstance(componentType, 0).getClass();
				}
				return type;
			}else{
				if(BaseBean.class.isAssignableFrom(type)){
					return BaseBean.class;
				}
				return type;
			}
		}
		return type;
	}
	private static final Class<?>[] wrapBaseBean(Class<?>... types){
		if(null != types){
			for(int i=0;i<types.length;++i){
				types[i] = wrapBaseBean(types[i]);
			}
		}
		return types;
	}
	static class ParamTypeBuilder{
		List<Class<?>> builder = Lists.newLinkedList();

		ParamTypeBuilder add(Class<?>type){
			builder.add(type);
			return this;
		}
		ParamTypeBuilder add(Class<?>[]types,int start){
			builder.addAll(Arrays.asList(Arrays.copyOfRange(types, start, types.length)));
			return this;
		}
		ParamTypeBuilder add(Class<?> type,Class<?> ...types){
			builder.add(type);
			builder.addAll(Arrays.asList(types));
			return this;
		}
		/**
		 * 对象索引指定的类型进行泛型归一化<br>
		 * 如果为{@link BaseBean}的子类则改为{@link BaseBean}，否则改为{@code normalClass} 
		 * @param index
		 * @param normalizeClass 归一化类型
		 * @return 当前对象
		 */
		ParamTypeBuilder genericNormalize(int index,Class<?> normalizeClass){
			try {
				Class<?> type = builder.get(index);
				if(BaseBean.class.isAssignableFrom(type)){
					builder.set(index, BaseBean.class);
				}else if(null != normalizeClass){
					builder.set(index, normalizeClass);
				}
			} catch (IndexOutOfBoundsException e) {
				throw new IllegalArgumentException(logString("INVALID index %s for  parameter types array", index));
			}
			return this;
		}
		/**
		 * 对象索引指定的类型进行泛型归一化<br>
		 * 如果为{@link BaseBean}的子类则改为{@link BaseBean}，否则改为{@code normalClass},
		 * 删除{@code index}之后的所有元素 
		 * @param index
		 * @param normalizeClass 归一化类型
		 * @return 当前对象
		 */
		ParamTypeBuilder normalizeLast(int index,Class<?> normalizeClass){
			try {
				Class<?> type = builder.get(index);
				if(BaseBean.class.isAssignableFrom(type)){
					builder.set(index, BaseBean.class);
				}else{
					builder.set(index, normalizeClass);
				}
				// 删除index之后续的所有元素
				while(builder.size() > index+1){
					builder.remove(index + 1);
				}
			} catch (IndexOutOfBoundsException e) {
				throw new IllegalArgumentException(logString("INVALID index %s for  parameter types array", index));
			}
			return this;
		}
		Class<?>[] build(){
			return builder.toArray(new Class<?>[0]);
		}
	}
	private static ParamTypeBuilder paramBuilder(){
		return new ParamTypeBuilder();
	}
	
	/**
	 * 调用执行方法调用,剥离封装在{@link InvocationTargetException}中的方法调用异常直接抛出
	 * @param method 方法对象(不可为{@code null})
	 * @param obj 方法调用对象
	 * @param input 方法调用参数
	 * @return 方法调用返回值
	 * @throws Throwable
	 */
	private static Object stripedInvoke(Method method,Object obj,Object... input) throws Throwable {
		try {
			return method.invoke(obj, input);
		} catch (InvocationTargetException e) {
			Throwable te = e.getTargetException();
			if(te != null){
//				if(debug){
////					log("InvocationTargetException:"+te.toString(), te);
//					log("InvocationTargetException:"+te.toString());
//				}
				/** 剥离出方法调用中产生的异常直接抛出 */ 
				throw te;
			}else{
				log(e.toString());
				throw e;
			}
		}
	}
	/**
	 * 方法调用接口
	 * @author guyadong
	 */
	interface Invoker {
		static final Object[] EMPTY_OBJECT_ARRAY = new Object[]{};
		/**
		 * 执行方法调用
		 * @param input 输入参数数组
		 * @return 调用返回值
		 * @throws Throwable 方法调用抛出异常
		 */
		Object invoke(Object[] input) throws Throwable;
	}
	private class ObjectInvoker implements Invoker{
		final Method method;
		ObjectInvoker(Method method) {
			this.method = method;
		}
		@Override
		public Object invoke(Object[] input) throws Throwable {
			return stripedInvoke(method, delegate, firstNonNull(input,EMPTY_OBJECT_ARRAY));
		}
		@Override
		public String toString() {
			StringBuilder builder = new StringBuilder();
			builder.append("\n");
			builder.append("    @Override\n");
			builder.append("    public ").append(signatureOf(method,true,true)).append("{\n");
			builder.append("        ");
			if(!isVoid(method.getReturnType())){
				builder.append("return ");
			}
			builder.append("delegate.").append(method.getName()).append("(");
			Class<?>[] paramTypes = method.getParameterTypes();
			for(int j = 0; j < paramTypes.length;++j){
				if(j > 0){
					builder.append(",");
				}
				builder.append("arg").append(j);
			}
			builder.append(");\n");
			builder.append("    }\n");
			return builder.toString();
		}
		
	}
	/**
	 * 方法调用对象，用于封装执行方法调用时的所有信息
	 * @author guyadong
	 *
	 */
	private class  MethodInvoker implements Invoker {
		/** 接口方法  */
		final Method def;
		/** {@link  #manager}中与接口方法({@link #def})对应的实现方法  */
		final Method impl;
		/**  执行方法调用的对象 */
		protected final BaseTableManager<? extends BaseBean> manager;
		/**  执行方法调用时除原有传入参数之外的附加参数列表(排在原输入参数之前) */
		protected final Object[] additionalParams;
		/** 调用参数转换器,用于生成调用方法({@link #impl})的参数 */
		private final Function<Object[], Object[]> argsMaker;
		/**
		 * @param def 接口方法
		 * @param impl 实现方法
		 * @param manager 执行调用的对象
		 * @param additionalParams 附加参数列表
		 */
		private MethodInvoker(Method def, Method impl,BaseTableManager<? extends BaseBean> manager, Object... additionalParams) {
			this.def = def;
			this.impl = impl;
			if(!Modifier.isPublic(impl.getModifiers())){
				/** 非public方法必须设置为可访问 */
				impl.setAccessible(true);	
			}			
			this.manager = checkNotNull(manager,"manager is null");
			this.additionalParams = firstNonNull(additionalParams, EMPTY_OBJECT_ARRAY);
			Class<?>[] paramTypes = impl.getParameterTypes();
			if(paramTypes.length == additionalParams.length + 1 && Object[].class.equals(paramTypes[additionalParams.length])){
				argsMaker = vaArgsMaker;
			}else if(additionalParams.length == 0){
				argsMaker = defaultArgsMaker;
			}else {
				argsMaker = addparamArgsMaker;
			}
		}
		/** 默认参数转换器，不对输入参数做任何修改原样返回 */
		private final Function<Object[], Object[]> defaultArgsMaker = new Function<Object[], Object[]>() {
			
			@Override
			public Object[] apply(Object[] input) {
				return input;
			}
		};
		/** 有附加参数的参数转换器，创建新的Object数组，将附加参数，原输入参数顺序复制到新数组返回 */
		private final Function<Object[], Object[]> addparamArgsMaker = new Function<Object[], Object[]>() {
			@Override
			public Object[] apply(Object[] input) {
				Object[] args = new Object[additionalParams.length + input.length];
				System.arraycopy(additionalParams, 0, args, 0, additionalParams.length);
				System.arraycopy(input, 0, args, additionalParams.length, input.length);
				return args;
			}
		};
		/** 
		 * 输入参数为变长参数数组的参数转换器, 创建新的Object数组,
		 * 将附加参数复制到新数组，并将输入参数数组做为一个整体添加到新数组最后返回 
		 */
		private final Function<Object[], Object[]> vaArgsMaker = new Function<Object[], Object[]>() {
			@Override
			public Object[] apply(Object[] input){
				Class<?>[] paramTypes = impl.getParameterTypes();
				Object[] args = new Object[paramTypes.length];
				System.arraycopy(additionalParams, 0, args, 0, additionalParams.length);
				if(input[0] instanceof Object[]){
					args[additionalParams.length] = input[0];
				}else{
					args[additionalParams.length] = input;
				}
				return args;
			}
		};
		@Override
		public Object invoke(Object[] input) throws Throwable {
			return stripedInvoke(impl, manager, argsMaker.apply(firstNonNull(input, EMPTY_OBJECT_ARRAY)));
		}		
		@Override
		public String toString() {
			
			StringBuilder builder = new StringBuilder();
			builder.append("\n");
			builder.append("    @Override\n");
			builder.append("    public ").append(signatureOf(def,true,true)).append("{\n");
			builder.append("        ");
			if(!isVoid(def.getReturnType())){
				builder.append("return ");
			}
			builder.append(manager == delegate? "delegate.": BaseTableManager.class.getName()+".instanceOf(" + manager.getClass().getName() + ".class).");
			builder.append(impl.getName());
			builder.append("(");
			int i=0;
			for(; i < additionalParams.length;++i){
				if(i>0){
					builder.append(",");
				}
				if(additionalParams[i] instanceof String){
					builder.append("\"" + additionalParams[i]  + "\"");
				} else if(additionalParams[i] instanceof Class){
					builder.append(((Class<?>)additionalParams[i]).getName()  + ".class");
				}else {
					builder.append(additionalParams[i]);
				}
			}
			Class<?>[] paramTypes = def.getParameterTypes();
			for(int j = 0;  j < paramTypes.length; ++j){
				if(i++ > 0){
					builder.append(",");
				}
				builder.append("arg").append(j);
			}
			builder.append(");\n");
			builder.append("    }\n");
			return builder.toString();
		}
	}
	private class SaveFullyInvoker extends MethodInvoker{
		/**
		 * @param def 接口方法
		 * @param impl 实现方法
		 */
		private SaveFullyInvoker(Method def, Method impl) {
			super(def, impl, delegate);
		}

		@Override
		public Object invoke(Object[] input) throws Throwable {
			return stripedInvoke(impl, manager, input[0],Arrays.copyOfRange(input, 1, input.length));
		}
		
		@Override
		public String toString() {
			
			StringBuilder builder = new StringBuilder();
			builder.append("\n");
			builder.append("    @Override\n");
			builder.append("    public ").append(signatureOf(def,true,true)).append("{\n");
			builder.append("        ").append("return ").append("delegate.").append(impl.getName()).append("(");
			Class<?>[] paramTypes = def.getParameterTypes();
			builder.append("arg0,new Object[]{");
			for(int j = 0;  j < paramTypes.length; ++j){
				if(j>0){
					builder.append(", ");
				}
				builder.append("arg").append(j);
			}
			builder.append("});\n");
			builder.append("    }\n");
			return builder.toString();
		}
	}
}
